package com.cuc.platform.core.componet.security;


import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import com.cuc.platform.core.componet.security.domain.SecurityAuthority;
import com.cuc.platform.core.componet.security.domain.SecurityUser;
import com.cuc.platform.core.componet.security.service.SecurityUserService;
import com.cuc.platform.core.componet.security.utils.Digests;
import com.cuc.platform.core.componet.security.utils.Encodes;

/**
 * 基于Shiro的自定义DbRealm
 * 
 * 改造自spring side4
 */
public class ShiroDbRealm extends AuthorizingRealm {
	
	public static void main(String[] args){
		
		 Map<String, String>  map =  entryptPassword("123");
		 System.out.println(map.get("salt"));
		 System.out.println(map.get("password"));
	}
	
	/**
	 * SHA-1密码生成
	 *   生成随机的salt并经过1024次 sha-1 hash
	 *   @param plainPassword 密码明文
	 *   @return map 包含密码和盐值
	 */
	public static  Map<String, String> entryptPassword(String plainPassword) {
		System.out.println("密码");
		byte[] saltByte = Digests.generateSalt(SALT_SIZE);
		//盐值
		String salt = Encodes.encodeHex(saltByte);
		
		byte[] hashPassword = Digests.sha1(plainPassword.getBytes(), saltByte, HASH_INTERATIONS);
		//密码
		String password = Encodes.encodeHex(hashPassword);
		
		Map<String, String> map = new HashMap<String, String>();
		map.put("salt", salt);
		map.put("password", password);
		
		return map;
	}

	/**
	 * 认证回调函数,登录时调用.
	 * 
	 * 判断登录账号是否合法
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		
		SecurityUser user = securityFacadeService.getUserByLoginName(token.getUsername());
		System.out.println(user.getLoginName()+"##"+user.getPassword()+"##"+user.getOrgId());
		if (user != null) {
			byte[] salt = Encodes.decodeHex(user.getSalt());
			SimpleAuthenticationInfo sa = new SimpleAuthenticationInfo(new ShiroUser(user.getId(), user.getLoginName(), user.getAliasName(),user.getOrgId()),
					user.getPassword(), ByteSource.Util.bytes(salt), getName());
			return sa;
//			return new SimpleAuthenticationInfo(user.getLoginName(),user.getPassword(),  getName());
		}
		
		return null;
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("授权信息");
		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
		List<Map<String, Object>> list = securityFacadeService.getUserWithRoles(shiroUser.loginName);
		
		if (list != null) {  
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();  
			for(Map<String, Object> m:list){
				//添加角色
				info.addRole((String)m.get("r_name"));
				// 基于Permission的权限信息  
				info.addStringPermissions(this.getAuthStrList((Long)m.get("r_id"))); 
			}

			return info;  
		} else {  
			return null;  
		}  
	}
	

	/**
	 * 设定Password校验的Hash算法与迭代次数.
	 */
	@PostConstruct
	public void initCredentialsMatcher() {
		System.out.println("哈设密码");
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(SecurityUserService.HASH_ALGORITHM);
		matcher.setHashIterations(SecurityUserService.HASH_INTERATIONS);

		setCredentialsMatcher(matcher);
	}


	/**
	 * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.
	 */
	public static class ShiroUser implements Serializable {
		private static final long serialVersionUID = -1373760761780840081L;
		public Long id;
		public String loginName;
		public String name;
		public Long orgId;
		
		public ShiroUser(Long id, String loginName, String name) {
			this.id = id;
			this.loginName = loginName;
			this.name = name;
		}
		
		public ShiroUser(Long id, String loginName, String name, Long orgId) {
			this.id = id;
			this.loginName = loginName;
			this.name = name;
			this.orgId = orgId;
		}

		public String getName() {
			return name;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return loginName;
		}


		/**
		 * 重载equals,只计算loginName;
		 */
		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			ShiroUser other = (ShiroUser) obj;
			if (loginName == null) {
				if (other.loginName != null) {
					return false;
				}
			} else if (!loginName.equals(other.loginName)) {
				return false;
			}
			return true;
		}
	}
	
	/**
	 * 根据角色id，构造权限名称List
	 * 
	 * @param roleId
	 * @return List<String>
	 */
	private List<String> getAuthStrList(Long roleId){
		if (null == roleId) return null;
		
		List<String> authNameList = new ArrayList<String>();
		
		List<SecurityAuthority> list = securityFacadeService.getAuthsByRoleId(roleId);
		final int len = list.size();
		for (int i=0;i<len;i++){
			SecurityAuthority auth = (SecurityAuthority)list.get(i);
			authNameList.add(auth.getName());
		}
		
		return authNameList;
	}
	
	private static final int HASH_INTERATIONS = 1024;
	private static final int SALT_SIZE = 8;
	
	/**
	 * Ioc
	 */
	@Resource
	private SecurityFacadeService securityFacadeService;

}
